package com.leather.user.api.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.leather.common.entity.User;
import com.leather.common.result.CodeMsg;
import com.leather.common.result.Result;
import com.leather.common.toolkits.*;
import com.leather.user.api.UserService;
import com.leather.user.mapper.UserMapper;
import com.leather.user.vo.UserVo;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Override
    public Result addUser(UserVo userVo) {

        Result result = userVo.validateAdd();
        if (!result.isSuccess()) {
            return result;
        }
        String token = getToken(userVo.getNumber(), userVo.getPassword());
        CheckKit.notEqual("-1", token, CodeMsg.ERROR_NUMBER_PASSWORD);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", token);
        HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(null, headers);
        String getInfoUrl = "http://jwgl.cqjtu.edu.cn/app.do?method=getUserInfo&xh=" + userVo.getNumber();
        String response = "";
        try {
            response = restTemplate.postForObject(getInfoUrl, requestEntity, String.class);
        } catch (Exception e) {
            return Result.error(CodeMsg.NET_OFFLINE);
        }
        JSONObject jsonObject = (JSONObject) JSON.parse(response);
        //校验token有效性
        CheckKit.check(!jsonObject.containsKey("token"), CodeMsg.ERROR_JWW_TOKEN);
        User user = new User();
        user.setId(0);
        user.setRealName(jsonObject.getString("xm"));
        user.setNumber(userVo.getNumber());
        user.setPassword(EncryptKit.MD5(userVo.getPassword()));
        user.setCollege(jsonObject.getString("yxmc"));
        user.setDepartment(jsonObject.getString("zymc"));
        user.setClassName(jsonObject.getString("bj"));
        user.setGrade(jsonObject.getString("nj"));
        user.setGender(jsonObject.getString("xb"));
        user.setNickName(StringKit.getRandomString(10));
        user.setDescription("签名是一种态度,我想我可以更酷");
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        CheckKit.check(save(user), CodeMsg.SERVER_ERROR);
        return getResult(userVo, user);
    }

    private String getToken(String username, String password) {
        String url = "http://jwgl.cqjtu.edu.cn/app.do?method=authUser&xh=" + username + "&pwd=" + password;
        //爬虫获取数据信息
        String responseString = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = (JSONObject) JSON.parse(responseString);
        return jsonObject.getString("token");

    }

    @Override
    public User getUserByNumber(String number) {
        return query().eq("number", number).one();
    }

    @Override
    public JSONObject getUserInfo(String number) {
        JSONObject obj = new JSONObject();
        User user = getUserByNumber(number);
        obj.put("user", user);
        obj.put("star", userMapper.selectTouchedCount(user.getId()));
        obj.put("touch", userMapper.selectTouchCount(user.getId()));
        return obj;
    }

    @Override
    public Result login(UserVo userVo) {
        User user = getUserByNumber(userVo.getNumber());
        if (null != user) {
            if (EncryptKit.MD5(userVo.getPassword()).equals(user.getPassword())) {
                if (user.getFlag() != 0) {
                    return Result.error(CodeMsg.FROZEN_USER);
                }
                return getResult(userVo, user);

            }
            return Result.error(CodeMsg.ERROR_PASSWORD);
        }
        return addUser(userVo);
    }

    @Override
    public Result getUserInfo(int nowId, int userId) {
        CheckKit.check(nowId>0,CodeMsg.ERROR_USER_ID);
        CheckKit.check(userId>0,CodeMsg.ERROR_USER_ID);
        JSONObject obj = new JSONObject();
        User user = getById(userId);
        CheckKit.check(user!=null,CodeMsg.ERROR_USER_ID);
        obj.put("user",user);
        int count = userMapper.getIsTouched(nowId,userId);
        boolean isTouched = count!=0;
        obj.put("isTouched",isTouched);
        return Result.success(obj);
    }

    private Result getResult(UserVo userVo, User user) {
        JSONObject obj = new JSONObject();
        obj.put("token", JwtKit.buildJWT(userVo.getNumber()));
        obj.put("user", user);
        obj.put("star", userMapper.selectTouchedCount(user.getId()));
        obj.put("touch", userMapper.selectTouchCount(user.getId()));
        return Result.success(obj);
    }

    @Override
    public Result changeImgUrl(String number, String imgUrl) {
        //CheckKit.notEmpty(number, CodeMsg.EMPTY_USER_NUMBER);
        CheckKit.notEmpty(number, CodeMsg.EMPTY_IMAGE_URL);
        return getFlag(number, "changeImgUrl", imgUrl);
    }

    @Override
    public User getUserByNickName(String nickName) {
        return query().eq("nick_name", nickName).one();
    }


    /**
     * 获取当月获取验证码的次数
     *
     * @param number
     * @return
     */
    private int countHistory(String number) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.allEq(generrateParam(number));
        return userMapper.countHistory(queryWrapper);

    }

    private Map<String, Object> generrateParam(String number) {
        LocalDate date = LocalDate.now();
        int year = date.getYear();
        int month = date.getMonthOfYear();

        Map<String, Object> params = Maps.newHashMap();
        params.put("number", number);
        params.put("year", year);
        params.put("month", month);
        return params;
    }

    /**
     * 插入获取验证码记录
     *
     * @param number
     * @return
     */
    private int insertHistory(String number) {
        LocalDate date = LocalDate.now();
        int year = date.getYear();
        int month = date.getMonthOfYear();
        return userMapper.insertHistory(number, year, month);
    }

    @Override
    public Result getMessage(String number, String phone) {

        //判断是否是手机号
        CheckKit.check(ValidateKit.isMobile(phone),CodeMsg.ERROR_PHONE);

        //判断当月获取验证码的次数
        int count = countHistory(number);
        CheckKit.check(count < 3, CodeMsg.OUT_OF_TIMES);
        //判断绑定的手机号是否与之前的相同
        User user = getUserByNumber(number);
        CheckKit.notEqual(phone, user.getPhone(), CodeMsg.DUPPY_PHONE);
        //判断该手机号是否已被其他用户绑定
        count = query().eq("phone", phone).count();
        CheckKit.check(count <= 0, CodeMsg.DUPPY_USER_PHONE);

        ValueOperations<String, String> operation = redisTemplate.opsForValue();
        //生成四位验证码
        String code = StringKit.getCode(4);
        CheckKit.check(MessageKit.sendMessage(phone, code), CodeMsg.ERROR_SEND_MESSAGE);
        //放入缓存redis
        operation.set(phone, code, 120, TimeUnit.SECONDS);
        count = insertHistory(number);
        CheckKit.check(count > 0, CodeMsg.SERVER_ERROR);
        return Result.success("ok");
    }

    @Override
    public Result setPhone(String number, String phone, String code) {
        ValueOperations<String, String> operation = redisTemplate.opsForValue();
        CheckKit.check(redisTemplate.hasKey(phone), CodeMsg.TIME_OUT_CODE);
        String val = operation.get(phone);
        CheckKit.equal(val, code, CodeMsg.ERROR_CODE);
        return getFlag(number, "setPhone", phone);

    }

    @Override
    public Result getTouched(int userId) {

        List<UserVo> touchList = userMapper.getTouchList(userId);
        return Result.success(touchList);
    }

    @Override
    public Result getStar(int userId) {

        List<UserVo> touchList = userMapper.getStar(userId);
        return Result.success(touchList);
    }

    @Override
    public Result changeNickName(String number, String nickName) {
        //CheckKit.notEmpty(number, CodeMsg.EMPTY_USER_NUMBER);
        CheckKit.notEmpty(nickName, CodeMsg.EMPTY_NICK_NAME);
        //判断是否存在相同昵称的用户
        User user = getUserByNickName(nickName);
        CheckKit.check(user == null, CodeMsg.DUPPY_NICKNAME);
        return getFlag(number, "changeNickName", nickName);
    }

    @Override
    public Result changeDescription(String number, String description) {
        // CheckKit.notEmpty(number, CodeMsg.EMPTY_USER_NUMBER);
        CheckKit.notEmpty(description, CodeMsg.EMPTY_DESCRIPTION);
        return getFlag(number, "changeDescription", description);
    }


    /**
     * 根据业务关键字返回flag
     *
     * @param number
     * @param ywgjz
     * @param data
     * @return
     */
    private Result getFlag(String number, String ywgjz, String data) {
        if ("changeDescription".equals(ywgjz)) {
            return update().eq("number", number).set("description", data).update() ? Result.success(data) : Result.error(CodeMsg.SERVER_ERROR);
        } else if ("changeNickName".equals(ywgjz)) {
            return update().eq("number", number).set("nick_name", data).update() ? Result.success(data) : Result.error(CodeMsg.SERVER_ERROR);
        } else if ("changeImgUrl".equals(ywgjz)) {
            return update().eq("number", number).set("img_url", data).update() ? Result.success(data) : Result.error(CodeMsg.SERVER_ERROR);
        } else if ("frozenUser".equals(ywgjz)) {
            return update().eq("id", number).set("flag", 1).update() ? Result.success(data) : Result.error(CodeMsg.ERROR_USER_ID);
        } else if ("setPhone".equals(ywgjz)) {
            return update().eq("number", number).set("phone", data).update() ? Result.success(data) : Result.error(CodeMsg.SERVER_ERROR);
        } else {
            return update().eq("id", number).set("flag", 0).update() ? Result.success(data) : Result.error(CodeMsg.ERROR_USER_ID);
        }
    }


    @Override
    public UserVo getUserVoById(int userId) {
        CheckKit.check(userId <= 0, CodeMsg.ERROR_USER_ID);
        return userMapper.getUserVoById(userId);
    }

    @Override
    public Result frozenUser(int userId) {
        CheckKit.check(userId <= 0, CodeMsg.ERROR_USER_ID);
        return getFlag(userId + "", "frozenUser", "0");
    }

    @Override
    public Result unFrozenUser(int userId) {
        CheckKit.check(userId <= 0, CodeMsg.ERROR_USER_ID);
        return getFlag(userId + "", "unFrozenUser", "1");
    }

    @Override
    public IPage<User> getUserListByPage(Page<User> page, String sort, String search) {
        return query().like(StringUtils.isNotBlank(search), "number", search).or().like(StringUtils.isNotBlank(search), "real_name", search).orderBy(true, "asc".equals(sort), "id").page(page);
    }

    @Override
    public Result touchUser(int userId, int touchId) {
        return getResult(userId,touchId,"touchUser");
    }

    @Override
    public Result deleteTouchUser(int userId, int touchId) {
        return getResult(userId,touchId,"deleteTouchUser");
    }

    private Result getResult(int userId,int touchId,String ywgjz){
        CheckKit.check(userId>0,CodeMsg.ERROR_USER_ID);
        CheckKit.check(touchId>0,CodeMsg.ERROR_USER_ID);
        int count=0;
        try {
            if("touchUser".equals(ywgjz)) {
                count = userMapper.touchUser(userId,touchId);
            }else{
                count = userMapper.deleteTouchUser(userId,touchId);
            }
        }catch (Exception e){
            return Result.error(CodeMsg.DUPPY_TOUCHED);
        }

        CheckKit.check(count>0,CodeMsg.SERVER_ERROR);
        return Result.success("");
    }
}
